﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Data;
using BEELab.Data;
using BEELab.Logic.ProgramManagement.SessionManagement;
using BEELab.Logic.ProgramManagement.VariableManagement;
using BEELab.Logic.ProgramManagement.StageManagement;
using System.Text;
using System.Text.RegularExpressions;

namespace BEELab
{
    public partial class FunctionSettings : System.Web.UI.Page
    {
        private Dictionary<string, VariableManagement.Variable> VariablesDictionary = new Dictionary<string,VariableManagement.Variable>();
        private Dictionary<int, BlockElements.BlockElement> BlockElementsDictionary = new Dictionary<int, BlockElements.BlockElement>();
        private Dictionary<int, PresentationElements.PresentationElement> PresentationElementsDictionary = new Dictionary<int, PresentationElements.PresentationElement>();
        private Dictionary<string, int> VariableNameIDDictionary = new Dictionary<string, int>();
        private Dictionary<string, string> OldNewElementName = new Dictionary<string, string>();

        public void LoadData(int ContainerID, int ProgramID)
        {
            int StageID = BEELab.Logic.ProgramManagement.FunctionManagement.GetSettingsStageID(ProgramID);

            SqlCommand command = new SqlCommand();
            command.CommandText = "SELECT * FROM BlockElements WHERE StageID=@StageID";
            command.Parameters.Add(new SqlParameter("@StageID", StageID));
            DataTable dt = DBHelper.ExecuteQuery(command);

            int id;
            BlockElementsDictionary.Clear();
            foreach (DataRow row in dt.Rows)
            {
                id = int.Parse(row["ID"].ToString());
                BlockElementsDictionary[id] = new BlockElements.BlockElement(id, dt);
            }

            command = new SqlCommand();
            command.CommandText = "SELECT * FROM PresentationElements WHERE StageID=@StageID";
            command.Parameters.Add(new SqlParameter("@StageID", StageID));
            dt = DBHelper.ExecuteQuery(command);

            PresentationElementsDictionary.Clear();
            foreach (DataRow row in dt.Rows)
            {
                id = int.Parse(row["ID"].ToString());
                PresentationElementsDictionary[id] = new PresentationElements.PresentationElement(id, dt);
            }

            command = new SqlCommand();
            command.CommandText = "SELECT Variables.ID, Variables.Name, Variables.Description, Variables.Scope, Variables.DefaultValue, ContainerElements.OriginalName FROM ContainerElements JOIN Variables ON (Variables.ID=ContainerElements.ElementID AND ContainerElements.Type='Variable') WHERE ContainerID=@ContainerID AND Type='Variable'";
            command.Parameters.Add(new SqlParameter("@ContainerID", ContainerID));
            dt = DBHelper.ExecuteQuery(command);

            VariablesDictionary.Clear();
            VariableNameIDDictionary.Clear();
            OldNewElementName.Clear();
            foreach (DataRow row in dt.Rows)
            {
                VariablesDictionary[row["Name"].ToString()] = new VariableManagement.Variable(row["Name"].ToString(), row["Description"].ToString(), row["Scope"].ToString(), row["DefaultValue"].ToString());
                VariableNameIDDictionary[row["Name"].ToString()] = int.Parse(row["ID"].ToString());
                OldNewElementName[row["OriginalName"].ToString()] = row["Name"].ToString();
            }
        }

        /// <summary>
        /// Occures on every page load (first time or Post Back)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.QueryString["ID"] != null && Request.QueryString["ID"].ToString().Equals("") == false && Request.QueryString["FunctionID"] != null && Request.QueryString["FunctionID"].ToString().Equals("") == false)
            {
                if (Request.QueryString["Complete"] == null)
                {
                    LoadData(int.Parse(Request.QueryString["ID"].ToString()), int.Parse(Request.QueryString["FunctionID"].ToString()));
                    Literal1.Text = GenerateStage(int.Parse(Request.QueryString["ID"].ToString()), int.Parse(Request.QueryString["FunctionID"].ToString()));
                }
                else
                {
                    LoadData(int.Parse(Request.QueryString["ID"].ToString()), int.Parse(Request.QueryString["FunctionID"].ToString()));
                    ManagePostedData();
                    RecordData(int.Parse(Request.QueryString["ID"].ToString()));
                    Literal1.Text = "<script>parent.$.fancybox.close();</script>";
                }
            }
        }

        private void RecordData(int ContainerID)
        {
            foreach (VariableManagement.Variable variable in VariablesDictionary.Values)
            {
                SqlCommand command = new SqlCommand();
                command.CommandText = "UPDATE Variables SET DefaultValue=@Value WHERE ID=@ID";
                command.Parameters.Add(new SqlParameter("@Value", variable.Value));
                command.Parameters.Add(new SqlParameter("@ID", VariableNameIDDictionary[variable.Name]));
                DBHelper.ExecuteNonQuery(command);
            }
        }

        private string TransformDescription(BlockElements.BlockElement Element)
        {
            return string.Concat("//", Element.Description.Replace("\n", "\n //"));
        }

        private string TransformContent(BlockElements.BlockElement Element)
        {
            if (Element.Type == "Code")
                return Element.Content;

            if (Element.Type == "Call")
                return Properties.Settings.Default.BlockPrefix + Element.Content + Properties.Settings.Default.BlockSuffix + ";";

            StringBuilder result = new StringBuilder("");

            if (Element.Name == Properties.Settings.Default.OnMessageBlockName)
            {
                result = new StringBuilder("function " + Element.Name + "(message){" + Environment.NewLine);
            }
            else
            {
                result = new StringBuilder("function " + Properties.Settings.Default.BlockPrefix + Element.Name + Properties.Settings.Default.BlockSuffix + "{" + Environment.NewLine);
            }

            for (int i = 0; i < Element.Children.Count; i++)
            {
                result.AppendLine(TransformElement(BlockElementsDictionary[Element.Children[Element.Children.Keys.ElementAt(i)]]));
            }

            if (Element.Name == Properties.Settings.Default.OnPostBlockName)
            {
                result.AppendLine("@POSTBACKJSCODE@");
            }

            result.AppendLine("}");

            return result.ToString();
        }

        private string TransformElement(BlockElements.BlockElement Element)
        {
            return string.Concat(TransformDescription(Element), Environment.NewLine, TransformContent(Element));
        }

        private string GenerateStage(int ContainerID, int FunctionID)
        {
            StringBuilder StageContent = new StringBuilder();

            StageContent.AppendLine("<script>");
            StageContent.AppendLine("//Define Variables");
            foreach (VariableManagement.Variable variable in VariablesDictionary.Values)
            {
                StageContent.AppendLine("var " + variable.Name + ";");
            }

            StageContent.AppendLine("//Load Variables");
            foreach (VariableManagement.Variable variable in VariablesDictionary.Values)
            {
                StageContent.AppendLine(variable.Name + " = \"" + Properties.Settings.Default.VariablePrefix + variable.Name + Properties.Settings.Default.VariableSuffix + "\";");
            }

            StageContent.AppendLine("//Logic Layer Functions");
            foreach (BlockElements.BlockElement element in BlockElementsDictionary.Values)
            {
                if (element.Type == "Block")
                {
                    StageContent.AppendLine(TransformElement(element));
                }
            }

            StageContent.AppendLine("$(document).ready(function(){ ");
            StageContent.AppendLine("$(window).keydown(function(event){ if(event.keyCode == 13) { event.preventDefault(); return false; } });  ");
            StageContent.AppendLine("OnLoad();  });");

            StageContent.AppendLine("</script>");

            StageContent.AppendLine("<!--Presentation Layer Placeholder-->");
            StageContent.AppendLine(Properties.Settings.Default.PresentationPrefix + Properties.Settings.Default.PresentationLayer + BEELab.Logic.ProgramManagement.FunctionManagement.GetSettingsStageID(FunctionID) + Properties.Settings.Default.PresentationSuffix);
            
            StageContent.Replace("@POSTBACKJSCODE@", GeneratePostJSCode(ContainerID, FunctionID));

            return HandlePlaceholders(StageContent.ToString());
        }

        private string HandlePlaceholders(string Content)
        {
            StringBuilder result = new StringBuilder(Content);

            Boolean flag = true;
            string str;
            int i = 0;
            while (flag && i < 1000)
            {
                flag = false;
                i++;
                str = result.ToString();

                foreach (string name in OldNewElementName.Keys)
                {
                    VariableManagement.Variable variable = VariablesDictionary[OldNewElementName[name]];
                    if (str.Contains(Properties.Settings.Default.VariablePrefix + name + Properties.Settings.Default.VariableSuffix))
                    {
                        flag = true;
                        result.Replace(Properties.Settings.Default.VariablePrefix + name + Properties.Settings.Default.VariableSuffix, variable.Value.Replace("\"", "\\\""));
                        
                    }

                    if (str.Contains(Properties.Settings.Default.VariableNamePrefix + name + Properties.Settings.Default.VariableNameSuffix))
                    {
                        flag = true;
                        result.Replace(Properties.Settings.Default.VariableNamePrefix + name + Properties.Settings.Default.VariableNameSuffix, variable.Name);
                    }
                }
                foreach (string name in OldNewElementName.Values)
                {
                    VariableManagement.Variable variable = VariablesDictionary[name];
                    if (str.Contains(Properties.Settings.Default.VariablePrefix + name + Properties.Settings.Default.VariableSuffix))
                    {
                        flag = true;
                        result.Replace(Properties.Settings.Default.VariablePrefix + name + Properties.Settings.Default.VariableSuffix, variable.Value.Replace("\"", "\\\""));
                        
                    }

                    if (str.Contains(Properties.Settings.Default.VariableNamePrefix + name + Properties.Settings.Default.VariableNameSuffix))
                    {
                        flag = true;
                        result.Replace(Properties.Settings.Default.VariableNamePrefix + name + Properties.Settings.Default.VariableNameSuffix, variable.Name);
                    }
                }

                foreach (PresentationElements.PresentationElement element in PresentationElementsDictionary.Values)
                {
                    if (str.Contains(Properties.Settings.Default.PresentationPrefix + element.Name + Properties.Settings.Default.PresentationSuffix))
                    {
                        flag = true;
                        result.Replace(Properties.Settings.Default.PresentationPrefix + element.Name + Properties.Settings.Default.PresentationSuffix, element.Content);
                    }
                }

                foreach (BlockElements.BlockElement element in BlockElementsDictionary.Values)
                {
                    if (element.Type == "Block")
                    {
                        if (str.Contains(Properties.Settings.Default.BlockPrefix + element.Name + Properties.Settings.Default.BlockSuffix))
                        {
                            flag = true;
                            result.Replace(Properties.Settings.Default.BlockPrefix + element.Name + Properties.Settings.Default.BlockSuffix, element.Name + "()");
                        }

                        if (str.Contains(Properties.Settings.Default.BlockPrefix + element.Name + Properties.Settings.Default.VariableSuffix))
                        {
                            flag = true;
                            result.Replace(Properties.Settings.Default.BlockPrefix + element.Name + Properties.Settings.Default.VariableSuffix, element.Name);
                        }
                    }
                }
            }

            return result.ToString();
        }

        private string GeneratePostJSCode(int ContainerID, int FunctionID)
        {
            StringBuilder result = new StringBuilder();
            result.AppendLine("var form = document.createElement(\"form\");");
            result.AppendLine("form.setAttribute(\"method\", \"POST\");");
            result.AppendLine("form.setAttribute(\"action\", \"" + "FunctionSettings.aspx?Complete=yes&" + "ID=" + ContainerID + "&FunctionID=" + FunctionID + "\");");
            result.AppendLine("var hiddenField;");

            foreach (VariableManagement.Variable variable in VariablesDictionary.Values)
            {
                result.AppendLine("hiddenField = document.createElement(\"input\");");
                result.AppendLine("hiddenField.setAttribute(\"type\", \"hidden\");");
                result.AppendLine("hiddenField.setAttribute(\"name\", \"" + variable.Name + "\");");
                result.AppendLine("hiddenField.setAttribute(\"value\", " + variable.Name + ");");
                result.AppendLine("form.appendChild(hiddenField);");
            }

            result.AppendLine("document.body.appendChild(form);");
            result.AppendLine("form.submit();");

            return result.ToString();
        }

        private void ManagePostedData()
        {
            foreach (string key in Request.Form.Keys)
            {
                if (VariablesDictionary.ContainsKey(key))
                {
                    VariablesDictionary[key].Value = Request.Form[key];
                }
            }
        }
    }
}